home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / pyshared / XKit / xorgparser.py next >
Encoding:
Python Source  |  2009-01-04  |  84.4 KB  |  1,918 lines

  1. #       xorgparser.py -- Core class of X-Kit's parser
  2. #       
  3. #       Copyright 2008 Alberto Milone <albertomilone@alice.it>
  4. #       
  5. #       This program is free software; you can redistribute it and/or modify
  6. #       it under the terms of the GNU General Public License as published by
  7. #       the Free Software Foundation; either version 2 of the License, or
  8. #       (at your option) any later version.
  9. #       
  10. #       This program is distributed in the hope that it will be useful,
  11. #       but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. #       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. #       GNU General Public License for more details.
  14. #       
  15. #       You should have received a copy of the GNU General Public License
  16. #       along with this program; if not, write to the Free Software
  17. #       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  18. #       MA 02110-1301, USA.
  19.  
  20. import sys
  21. from sys import stdout, stderr
  22. import copy
  23.  
  24.  
  25. class IdentifierException(Exception):
  26.     '''Raise if no identifier can be found'''
  27.     pass
  28.  
  29. class OptionException(Exception):
  30.     '''Raise when an option is not available.'''
  31.     pass
  32.    
  33. class SectionException(Exception):
  34.     '''Raise when a section is not available.'''
  35.     pass
  36.  
  37. class ParseException(Exception):
  38.     '''Raise when a postion is not available.'''
  39.     pass
  40.  
  41. class Parser:
  42.     '''Only low-level methods here.
  43.     
  44.     See the xutils.XUtils subclass for higher-level methods.'''
  45.     def __init__(self, source=None):
  46.         '''source = can be an object or a file. If set to None (default)
  47.                  Parser will start from scratch with an empty
  48.                  configuration.
  49.         
  50.         Public:
  51.         
  52.         self.comments = stores the commented lines located outside of the
  53.                         sections in the xorg.conf.
  54.         
  55.         self.globaldict['Comments'] = stores the commented lines located
  56.                         inside of the sections in the xorg.conf.
  57.         
  58.         self.globaldict = a global dictionary containing all the sections
  59.                           and options. For further information on 
  60.                           self.globaldict, have a look at self.__process()
  61.                           and at getValue().
  62.         
  63.         self.requireid = a list of the sections which require to have an
  64.                          "Identifier" set in the xorg.conf (e.g. Device
  65.                          sections).
  66.         
  67.         self.identifiers = a dictionary of the sections which require identi
  68.                            fiers.
  69.         
  70.         self.sections = a tuple containing the names of all
  71.                         the sections which self.__process() will look for
  72.                         in the xorg.conf. Sections with other names
  73.                         will be ignored by self.__process().
  74.         
  75.         self.references = a list containing the names of all the possible
  76.                           references.'''
  77.         
  78.         self.subsection = 'SubSection'
  79.         self.commentsection = 'Comments'
  80.         self.source = source
  81.         self.sections = ('InputDevice',
  82.                     'Device',
  83.                     'Module',
  84.                     'Monitor',
  85.                     'Screen',
  86.                     'ServerLayout',
  87.                     'ServerFlags',
  88.                     'Extensions',
  89.                     'Files', 
  90.                     'DRI', 
  91.                     'VideoAdaptor', 
  92.                     'Vendor', 
  93.                     'Modes',
  94.                     'SubSection',
  95.                     'Comments')
  96.         self.requireid = [
  97.                           'InputDevice',
  98.                           'Device',
  99.                           'Monitor',
  100.                           'Screen',
  101.                           'ServerLayout'
  102.                          ]
  103.         self.references = [
  104.                            'Device',
  105.                            'InputDevice',
  106.                            'Monitor',
  107.                            'Screen'
  108.                           ]
  109.         
  110.         self.identifiers = {}.fromkeys(self.requireid)
  111.         
  112.         self.comments = []
  113.         self.globaldict = {}.fromkeys(self.sections, 0)
  114.         for elem in self.globaldict:
  115.             self.globaldict[elem] = {}
  116.         
  117.         self.__process()
  118.         
  119.         
  120.             
  121.     def __process(self):
  122.         '''Perform a sanity check of the file and fill self.globaldict with
  123.         all the sections and subsections in the xorg.conf
  124.         
  125.         
  126.         empty = is the file empty? If yes, then don't check if:
  127.             * the last section is not complete
  128.             * there are duplicates
  129.         
  130.         hasSection:
  131.             * == True: a section is already open
  132.             * == False: a section is closed and/or a new section can be opened
  133.             
  134.         hasSubSection:
  135.             * == True: a subsection is already open
  136.             * == False: a section is closed and/or a new section can be opened
  137.             
  138.         sectionFlag: 
  139.             * == '':a section is closed and/or a new section can be opened
  140.             * == the name the current section
  141.         
  142.         sectionTags = counter of the number of Section and EndSection strings
  143.         subSectionTags = counter of the number of SubSection and EndSubSection
  144.                          strings
  145.         
  146.         linesList = the list of the lines in the source object.
  147.         
  148.         globaliters = counts how many times each kind of section
  149.                              (sectionFlag) is found in the xorg.conf'''
  150.         
  151.         #See if the source is a file or a file object
  152.         #and act accordingly
  153.         file = self.source
  154.         if file == None:
  155.             linesList = []
  156.         else:
  157.             if not hasattr(file, 'write'):#it is a file
  158.                 myfile = open(file, 'r')
  159.                 linesList = myfile.readlines()
  160.                 myfile.close()
  161.             else:#it is a file object
  162.                 linesList = file.readlines()
  163.         
  164.         
  165.         # Create a dictionary such as the following:
  166.         # {'Device': {}, 'InputDevice': {}}
  167.         
  168.         globaliters = {}.fromkeys(self.sections, 0)        
  169.         
  170.         empty = True
  171.         
  172.         hasSection = False
  173.         hasSubSection = False
  174.         sectionFlag = ''
  175.         
  176.         sectionTags = 0
  177.         subSectionTags = 0
  178.         
  179.         it = 0
  180.         for line in linesList:
  181.             if line.strip().startswith('#'):
  182.                 if hasSection == False:
  183.                     self.comments.append(line)
  184.                 else:#hasSection == True
  185.                     sectionposition = globaliters[sectionFlag]
  186.                     if hasSubSection == False:
  187.                         self.globaldict[self.commentsection].setdefault(sectionFlag, {})
  188.                         self.globaldict[self.commentsection][sectionFlag].setdefault(sectionposition, {})
  189.                         self.globaldict[self.commentsection][sectionFlag][sectionposition].setdefault('identifier', None)
  190.                         self.globaldict[self.commentsection][sectionFlag][sectionposition].setdefault('position', sectionposition)
  191.                         self.globaldict[self.commentsection][sectionFlag][sectionposition].setdefault('section', None)
  192.                         self.globaldict[self.commentsection][sectionFlag][sectionposition].setdefault('options', [])
  193.                         self.globaldict[self.commentsection][sectionFlag][sectionposition]['options'].append(line.strip())
  194.                     else:#hasSubSection == True
  195.                         curlength = globaliters[self.subsection]
  196.                         self.globaldict[self.commentsection].setdefault(self.subsection, {})
  197.                         self.globaldict[self.commentsection][self.subsection].setdefault(curlength, {})
  198.                         self.globaldict[self.commentsection][self.subsection][curlength].setdefault('identifier', subSectionId)
  199.                         self.globaldict[self.commentsection][self.subsection][curlength].setdefault('position', sectionposition)
  200.                         self.globaldict[self.commentsection][self.subsection][curlength].setdefault('section', sectionFlag)
  201.                         self.globaldict[self.commentsection][self.subsection][curlength].setdefault('options', [])
  202.                         self.globaldict[self.commentsection][self.subsection][curlength]['options'].append(line.strip())
  203.                         
  204.                 
  205.                 
  206.             # See if the name of the section is acceptable
  207.             # i.e. included in self.sections
  208.             elif line.lower().strip().startswith('section'):#Begin Section
  209.                 testLineFound = False
  210.                 for sect in self.sections:
  211.                     if line.lower().find('"' + sect.lower() + '"') != -1:
  212.                         testLineFound = True
  213.                         section = sect
  214.                         break
  215.                 if not testLineFound:
  216.                     # e.g. in case the name of the section is not
  217.                     # recognised:
  218.                     # Section "whatever"
  219.                     error = 'The name in the following line is invalid for a section:\n%s' % (line)
  220.                     raise ParseException(error)
  221.                 else:
  222.                     if hasSection == False:
  223.                         sectionTags += 1
  224.  
  225.                         sectionFlag = section
  226.                         empty = False
  227.                         hasSection = True
  228.                     else:
  229.                         error = 'Sections cannot be nested in other sections.'
  230.                         raise ParseException(error)
  231.             elif line.lower().strip().startswith('endsection') == True:#End Section
  232.                 sectionTags += 1
  233.                 if hasSection == True and hasSubSection == False:
  234.                     globaliters[sectionFlag] += 1
  235.                     
  236.                     sectionFlag = ''
  237.                     hasSection = False
  238.                 else:
  239.                     error = 'An EndSection is in the wrong place.'
  240.                     raise ParseException(error)
  241.             elif line.lower().strip().startswith('subsection') == True:#Begin SubSection
  242.                 subSectionTags += 1
  243.                 
  244.                 if hasSection == True and hasSubSection == False:
  245.                     hasSubSection = True
  246.                     subSectionId = line[line.find('"')+1: line.rfind('"')].strip()
  247.                     
  248.                     self.globaldict.setdefault(self.subsection, {})
  249.                     curlength = globaliters[self.subsection]
  250.                     self.globaldict[self.subsection][curlength] = {}
  251.                     '''self.globaldict - keys:
  252.                     
  253.                     section =  the section in which the subsection is
  254.                                 located (e.g. "Screen")
  255.                     position = e.g. in key 0 of the 
  256.                                 self.globaldict['Screen']
  257.                     identifier = e.g. 'Display' (in SubSection "Display")
  258.                     options = a list of lines with the options'''
  259.                     
  260.                     self.globaldict[self.subsection][curlength]['section'] = sectionFlag
  261.                     try:
  262.                         self.globaldict[self.subsection][curlength]['position'] = globaliters[sectionFlag]
  263.                     except KeyError:
  264.                         error = 'SubSections can be nested only in well formed sections.'
  265.                         raise ParseException(error)
  266.                     self.globaldict[self.subsection][curlength]['identifier'] = subSectionId
  267.                     self.globaldict[self.subsection][curlength]['options'] = []
  268.                 
  269.                 else:
  270.                     error = 'SubSections can be nested only in well formed sections.'
  271.                     raise ParseException(error)
  272.                 
  273.             elif line.lower().strip().startswith('endsubsection') == True:#End SubSection
  274.                 subSectionTags += 1
  275.                 
  276.                 if hasSubSection == True:
  277.                     hasSubSection = False
  278.                     globaliters[self.subsection] += 1
  279.                 else:
  280.                     error = 'SubSections can be closed only after being previously opened.'
  281.                     raise ParseException(error)
  282.             else:
  283.                 if sectionFlag != '':#any other line
  284.                     if line.strip() != '':#options
  285.                         if hasSubSection == True:
  286.                             '''
  287.                             section =  the section in which the subsection is
  288.                                        located (e.g. "Screen")
  289.                             position = e.g. in key 0 of the 
  290.                                        self.globaldict['Screen']
  291.                             identifier = e.g. 'Display' (in SubSection "Display")
  292.                             options = a list of lines with the options
  293.                             '''
  294.                             self.globaldict[self.subsection][curlength]['options'].append('\t' + line.strip() + '\n')
  295.                         else:
  296.                             self.globaldict.setdefault(sectionFlag, {})
  297.                             curlength = globaliters[sectionFlag]
  298.                             self.globaldict[sectionFlag].setdefault(curlength, []).append('\t' + line.strip() + '\n')
  299.             it += 1
  300.         
  301.         if not empty:
  302.             # If the last section is not complete
  303.             if sectionTags % 2 != 0 or subSectionTags % 2 != 0:
  304.                 error = 'The last section is incomplete.'
  305.                 raise ParseException(error)
  306.             
  307.             # Fill self.identifiers
  308.             self.getIds()
  309.             
  310.  
  311.             # Make sure that the configuration file is compliant with
  312.             # the rules of xorg
  313.  
  314.             self.__complianceRules()
  315.             
  316.         else:
  317.             self.getIds()
  318.     
  319.     def __complianceRules(self):
  320.         '''This method contains the several checks which can guarantee
  321.         compliance with the syntax rules of the xorg.conf'''
  322.         
  323. #        '''
  324. #        Raise an exception if there are duplicate options i.e.
  325. #        options (not references) of the same kind with the same
  326. #        or with a different value.
  327. #        
  328. #        e.g. Driver "nvidia" and Driver "intel" cannot coexist in the
  329. #        same Device section.
  330. #        '''
  331. #        if len(self.checkDuplicateOptions()) > 0:
  332. #            error = 'There cannot be Duplicate Options:\n%s' % (str(self.checkDuplicateOptions()))
  333. #            raise ParseException(error)
  334.             
  335.         
  336.         # Raise an exception if there are duplicate sections i.e. 
  337.         # sections of the same kind (e.g. "Device") with the same 
  338.         # identifier.
  339.         # 
  340.         # e.g. The following configuration is not allowed:
  341.         # 
  342.         # Section "Device"
  343.         #     Identifier "My Device"
  344.         # EndSection
  345.         # 
  346.         # Section "Device"
  347.         #     Identifier "My Device"
  348.         # EndSection
  349.         if len(self.getDuplicateSections()) > 0:
  350.             error = 'There cannot be Duplicate Sections:\n%s' % (str(self.getDuplicateSections()))
  351.             raise ParseException(error)
  352.         
  353.         
  354.         # One word entries are not acceptable as either options or references.
  355.         # If one is found, ParseException will be raised.
  356.         self.validateOptions()
  357.         
  358.         
  359.         # Raise an exception if there are broken references i.e. references
  360.         # to sections which don't exist.
  361.         # 
  362.         # For example, if the xorg.conf were the following:
  363.         # 
  364.         # Section "Device"
  365.         #     Identifier "Another Device"
  366.         # EndSection
  367.         # 
  368.         # Section "Screen"
  369.         #     Identifier "My Screen"
  370.         #     Device "My Device"
  371.         # EndSection
  372.         # 
  373.         # There would be no Device section which has "My Device" as an identifier
  374.         broken = self.getBrokenReferences()
  375.         
  376.         it = 0
  377.         for section in broken:
  378.             it += len(broken[section])
  379.         if it > 0:
  380.             error = 'There cannot be Broken References:\n%s' % (str(broken))
  381.             raise ParseException(error)
  382.         
  383.         
  384.         # If there are sections which don't have an identifier
  385.         # but they should (i.e. they are in self.requireid)
  386.         # 
  387.         # NOTE: if there are empty sections without an identifier
  388.         # e.g. Section "Device"
  389.         #      EndSection
  390.         #         
  391.         #      they won't trigger the ParseException but won't
  392.         #      cause any problem since they will be completely
  393.         #      ignored and won't appear in the target file.
  394.         for section in self.requireid:
  395.             if len(self.globaldict[section]) != len(self.identifiers[section]):
  396.                 error = 'Not all the sections which require an identifier have an identifier.'
  397.                 raise ParseException(error)
  398.         
  399.         # The ServerLayout section must have at least 1 reference to a "Screen"
  400.         # section
  401.         if len(self.globaldict['ServerLayout']) > 0:
  402.             for section in self.globaldict['ServerLayout']:
  403.                 screenReferences = self.getReferences('ServerLayout', section, reflist=['Screen'])
  404.                 if len(screenReferences['Screen']) == 0:
  405.                     error = 'The ServerLayout section must have at least 1 reference to a "Screen" section.'
  406.                     raise ParseException(error)
  407.             
  408.         
  409.         # No more than one default ServerLayout can be specified in the
  410.         # ServerFlags section
  411.         defaultLayout = self.getDefaultServerLayout()
  412.         if len(defaultLayout) > 0:
  413.             if len(defaultLayout) > 1:
  414.                 error = 'No more than one default ServerLayout can be specified in the ServerFlags section.'
  415.                 raise ParseException(error)
  416.             
  417.             if not self.isSection('ServerLayout', position=defaultLayout[0]):
  418.                 error = 'The default ServerLayout does not exist'
  419.                 raise ParseException(error)
  420.         
  421.     def getIds(self):
  422.         '''Fill self.identifiers so that it has the section types as keys and a
  423.         list of tuples as values. The tuples contain the identifier and the
  424.         position of each section.
  425.         
  426.         NOTE: this method is called automatically in xutils when a section is
  427.         created but in xorgparser it is necessary to call it manually after
  428.         creating a new section which requires an identifier
  429.         
  430.         Here's a basic scheme:
  431.         
  432.         self.identifiers = {section_type1: [
  433.                                         (identifier1, position1),
  434.                                         (identifier2, position2)
  435.                                       ], etc.
  436.                            }
  437.         
  438.         Concrete example:
  439.         
  440.         self.identifiers = {'Device': [
  441.                                         ('Configured Video Device', 0),
  442.                                         ('Another Video Device', 1)
  443.                                       ],
  444.                             'Screen': [
  445.                                         ('Configured Screen Device', 0),
  446.                                         ('Another Screen Device', 1)
  447.                                       ],
  448.                            } '''
  449.         
  450.         for sect in self.requireid:#identifiers.keys():
  451.             self.identifiers[sect] = []
  452.             it = 0
  453.             for elem in self.globaldict[sect]:
  454.                 try:
  455.                     identifier = self.getValue(sect, 'Identifier', it)
  456.                 except (OptionException, SectionException):#if no identifier can be found
  457.                     error = 'No Identifier for section %s, position %d, can be found.' % (sect, elem)
  458.                     raise ParseException(error)
  459.                 try:
  460.                     identifier.append('')
  461.                     identifier = identifier[0]
  462.                 except AttributeError:
  463.                     pass
  464.                 
  465.                 self.identifiers[sect].append((identifier, it))
  466.                 it += 1
  467.     
  468.     def validateOptions(self):
  469.         '''One word entries are not acceptable as either options or references.
  470.         If one is found, ParseException will be raised.'''
  471.         
  472.         # Sections in sectionsWhitelist won't be validated
  473.         sectionsWhitelist = ['Files', 'Comments']
  474.         optionsWhitelist = ['endmode']
  475.         for section in self.sections:
  476.             if section not in sectionsWhitelist:
  477.                 for position in self.globaldict[section]:
  478.                     if section == self.subsection:#'SubSection':
  479.                         options = self.globaldict[section][position]['options']
  480.                     else:
  481.                         options = self.globaldict[section][position]
  482.                     
  483.                     
  484.                     for option in options:
  485.                         option = option.strip()
  486.                         if option.find('#') != -1:#remove comments
  487.                             option = option[0: option.find('#')]
  488.                         
  489.                         error = 'The following option is invalid: %s' % (option.strip())
  490.                         
  491.                         optbits = self.__cleanForDuplicates(option, includenull=True)
  492.                         
  493.                         if len(optbits) == 1 and optbits[0].strip().lower() not in optionsWhitelist:#ERROR
  494.                             
  495.                             raise ParseException(error)
  496.                         
  497.                         if not optbits[0][0].isalpha():
  498.                             raise ParseException(error)
  499.     
  500.     def getDuplicateOptions(self, section, position):
  501.         '''See if there are duplicate options in a section (it is ok to have duplicated
  502.         references) e.g. several Load options, or Screen, etc.'''
  503.         
  504.         blacklist = ['driver', 'busid', 'identifier']
  505.         total = []
  506.         duplicates = []
  507.         
  508.         if section == 'SubSection':
  509.             options = self.globaldict[section][position]['options']
  510.         else:
  511.             options = self.globaldict[section][position]
  512.         
  513.         
  514.         for option in options:
  515.             option = option.strip()
  516.             if option.find('#') != -1:#remove comments
  517.                 option = option[0: option.find('#')]
  518.             
  519.             optbits = self.__cleanForDuplicates(option)
  520.             
  521.             # optbits may look like this:
  522.             # 
  523.             # ['Option', 'TestOption1', '0']
  524.             # 
  525.             # or
  526.             # ['Screen', 'My screen 1']
  527.             try:
  528.                 if optbits[0].lower() in blacklist:
  529.                     total.append(optbits[0])
  530.                 elif optbits[0].lower() == 'option':
  531.                     if len(optbits) > 1 and optbits[1] != None:
  532.                         '''
  533.                         make sure it's not a broken option e.g.
  534.                           Option
  535.                         '''
  536.                         total.append(optbits[1])
  537.             except (AttributeError, IndexError):
  538.                 pass
  539.         final = {}
  540.         for option in total:
  541.             if final.get(option) != None:
  542.                 duplicates.append(option)
  543.             else:
  544.                 final[option] = option
  545.         return duplicates
  546.         
  547.     def checkDuplicateOptions(self):
  548.         '''Look for and return duplicate options in all sections'''
  549.         
  550.         duplicates = {}
  551.         for section in self.globaldict:
  552.             for elem in self.globaldict[section]:
  553.                 duplopt = self.getDuplicateOptions(section, elem)
  554.                 if len(duplopt) > 0:
  555.                     duplicates.setdefault(section, {}).setdefault(elem, duplopt)
  556.         
  557.         return duplicates
  558.         
  559.     def __cleanForDuplicates(self, option, includenull=None):
  560.         '''Clean the option and return all its components in a list
  561.         
  562.         includenull - is used only by validateOptions() and makes
  563.         sure that options with a null value assigned in quotation
  564.         marks are not considered as one-word options'''
  565.         
  566.         #print '\nCLEAN', repr(option)
  567.         optbits = []
  568.         optbit = ''
  569.         it = 0
  570.         quotation = 0
  571.         optcount = option.count('"')
  572.         if optcount > 0:#dealing with a section option
  573.             for i in option:
  574.                 #print 'i', repr(i), 'optbit', optbit
  575.                 if not i.isspace():
  576.                     if i == '"':
  577.                         quotation += 1
  578.                     else:
  579.                         optbit += i
  580.                 else:    
  581.                 
  582.                     if quotation % 2 != 0:
  583.                         optbit += i
  584.                         
  585.                     else:
  586.                         if len(optbit) > 0:
  587.                             optbits.append(optbit)
  588.                             #print 'i=', i, 'optbit=', optbit
  589.                             optbit = ''
  590.                         
  591.                 if it == len(option) - 1:
  592.                     if optbit != '':
  593.                         optbits.append(optbit)
  594.                         #print 'i=END', 'optbit=', optbit
  595.                 it += 1            
  596.         else:#dealing with a subsection option
  597.             for i in option:
  598.                 #print 'i', repr(i), 'optbit', optbit
  599.                 if not i.isspace():
  600.                     optbit += i
  601.                 else:    
  602.                     if len(optbit) > 0:
  603.                         optbits.append(optbit)
  604.                         #print 'i=', i, 'optbit=', optbit
  605.                         optbit = ''
  606.                         
  607.                 if it == len(option) - 1:
  608.                     if optbit != '':
  609.                         optbits.append(optbit)
  610.                         #print 'i=END', 'optbit=', optbit
  611.                     else:
  612.                         if includenull:
  613.                             optbit = ''
  614.                             optbits.append(optbit)
  615.                 it += 1
  616.         
  617.         if includenull and len(optbits) != optcount/2 +1:
  618.             # e.g. if the option looks like the following:
  619.             # 
  620.             # Modelname ""
  621.             # 
  622.             # add a '' which wouldn't be caught by this method otherwise.
  623.             optbit = ''
  624.             optbits.append(optbit)
  625.         
  626.         return optbits
  627.     
  628.     def getDuplicateSections(self):
  629.         '''Return a dictionary with the duplicate sections i.e. sections
  630.         of the same kind, with the same identifier'''
  631.         
  632.         duplicates = {}
  633.         for section in self.identifiers:
  634.             temp = []
  635.             for sect in self.identifiers[section]:
  636.                 temp.append(sect[0])
  637.             for elem in temp:
  638.                 if temp.count(elem) > 1:
  639.                     duplicates.setdefault(section, {}).setdefault(elem, temp.count(elem))
  640.  
  641.         return duplicates
  642.     
  643.     
  644.     def addOption(self, section, option, value, optiontype=None, position=None, reference=None, prefix='"'):
  645.         '''Add an option to a section
  646.         
  647.         section= the section which will have the option added
  648.         option= the option to add
  649.         value= the value which will be assigned to the option
  650.         position= e.g. 0 (i.e. the first element in the list of Screen
  651.                       sections)
  652.         optiontype= if set to "Option" it will cause the option to look like
  653.                     the following:
  654.                     Option "NameOfTheOption" "Value"
  655.                     
  656.                     Otherwise it will look like the following:
  657.                     NameOfTheOption "Value"
  658.         position= e.g. 0 (i.e. the first element in the list of Screen
  659.                       sections)
  660.         reference= used only in a particular case of reference (see addReference)
  661.         
  662.         prefix= usually quotation marks are used for the values (e.g. "True")
  663.                 however sometimes they don't have to be used
  664.                 (e.g. DefaultDepth 24) and prefix should be set to '' instead of
  665.                 '"'  '''
  666.         refSections = ['device']
  667.         #prefix = '"'#values are always in quotation marks
  668.         if position != None:
  669.             if self.globaldict[section].get(position) == None:
  670.                 raise SectionException
  671.             if reference:
  672.                 # Remove an option if it has a certain assigned value. We want
  673.                 # to do this when removing a reference.
  674.                 self.removeOption(section, option, value=value, position=position)
  675.                 #print 'Remove', option, 'from', section, 'position', position
  676.             else:
  677.                 # value has to be set to None, however there is no way to do so
  678.                 # other than this since addOption() cannot be called with 
  679.                 # value=None. Hence the need for this ugly nested if-block.
  680.                 self.removeOption(section, option, position=position)
  681.         else:
  682.             #print 'Remove', option, 'from all', section
  683.             self.removeOption(section, option)
  684.         if optiontype == None:
  685.             if reference == None:
  686.                 toadd = '\t' + option + '\t' + prefix + str(value) + prefix + '\n'
  687.             else:
  688.                 if section.strip().lower() not in refSections:
  689.                     # e.g. Screen "New Screen"
  690.                     toadd = '\t' + option + '\t' + prefix + str(value) + prefix + '\n'
  691.                 else:
  692.                     # e.g. Screen 0
  693.                     # which is used for Xinerama setups in the Device section
  694.                     toadd = '\t' + option + '\t' + str(value) + '\n'
  695.         else:
  696.             toadd = '\t' + optiontype + '\t' + '"' + option + '"' + '\t' \
  697.             + prefix + str(value) + prefix + '\n'
  698.                     
  699.         if len(self.globaldict[section]) == 0:
  700.             self.globaldict[section] = {}
  701.             self.globaldict[section][0] = []
  702.             if section in self.requireid:
  703.                 identifier = '\tIdentifier\t"Default ' + section + '"\n'
  704.                 self.globaldict[section][0].append(identifier)
  705.         if position == None:
  706.             for elem in self.globaldict[section]:
  707.                 self.globaldict[section][elem].append(toadd)
  708.         else:
  709.             self.globaldict[section][position].append(toadd)
  710.         
  711.     def __getOptionsToBlacklist(self, section, option, value=None, position=None, reference=None):
  712.         '''Private method shared by RemoveOption and CommentOutOption'''
  713.         toremove = {}
  714.         if len(self.globaldict[section]) != 0:#if the section exists
  715.  
  716.             if position == None:
  717.                 #print 'Removing', option, 'from all', section, 'sections'
  718.                 for elem in self.globaldict[section]:
  719.                     it = 0
  720.                     for line in self.globaldict[section][elem]:
  721.                         if value != None:
  722.                             #print 'line =', line, 'option=', option, 'value', value
  723.                             if line.lower().find(option.lower()) != -1 and line.lower().find(value.lower()) != -1:
  724.                                 toremove.setdefault(elem, []).append(it)
  725.                         else:
  726.                             if line.lower().find(option.lower()) != -1:
  727.                                 toremove.setdefault(elem, []).append(it)
  728.                         it += 1
  729.             else:
  730.                 if self.globaldict[section].get(position) == None:
  731.                     return
  732.                 else:
  733.                     #print 'Removing', option, 'from', section, 'position', position
  734.                     it = 0
  735.                     for line in self.globaldict[section][position]:
  736.                         if value != None:
  737.                             # Remove the option only if it has a certain value
  738.                             # assigned. This is useful in case we want to remove
  739.                             # a reference to a certain Section from another section:
  740.                             # e.g. Screen "Generic Screen".
  741.                             if line.lower().find(option.lower()) != -1 and line.lower().find(value.lower()) != -1:
  742.                                 toremove.setdefault(position, []).append(it)
  743.                         else:
  744.                             # Remove the option without caring about the assigned
  745.                             # value
  746.                             if line.lower().find(option.lower()) != -1:
  747.                                 toremove.setdefault(position, []).append(it)
  748.                         it += 1
  749.         return toremove
  750.         
  751.     def removeOption(self, section, option, value=None, position=None, reference=None):
  752.         '''Remove an option from a section.
  753.         
  754.         section= the section which will have the option removed
  755.         option= the option to remove
  756.         value= if you want to remove an option only if it has a certain value
  757.         position= e.g. 0 (i.e. the first element in the list of Screen
  758.                       sections)'''
  759.         
  760.         toremove = self.__getOptionsToBlacklist(section, option, value, position, reference)
  761.         for part in toremove:
  762.             modded = 0
  763.             for line in toremove[part]:
  764.                 realpos = line - modded
  765.                 del self.globaldict[section][part][realpos]
  766.                 modded += 1
  767.  
  768.     def makeSection(self, section, identifier=None):
  769.         '''Create a new section and return the position of the section in the list
  770.         of sections of the same type (e.g. "Screen") so as to make it available
  771.         in case the user wants to add some options to it.
  772.         
  773.         The identifier and the position of the new section is added to 
  774.         self.identifiers[section]
  775.         
  776.         section= the section to create
  777.         identifier= the identifier of a section (if the section requires an
  778.                     identifier)'''
  779.         
  780.         position  = len(self.globaldict[section])
  781.         
  782.         if section in self.requireid:
  783.             if identifier != None:
  784.                 option = 'Identifier'
  785.                 # Don't create a new section if one of the same kind and with the same 
  786.                 # 'Identifier' is found
  787.                 create = True
  788.                 for sub in self.globaldict[section]:
  789.                     if self.getValue(section, option, sub):
  790.                         try:
  791.                             if self.getValue(section, option, sub).strip().lower() == identifier.strip().lower():
  792.                                 create = False
  793.                                 break
  794.                         except AttributeError:
  795.                             for elem in self.getValue(section, option, sub):
  796.                                 #print 'elem=', elem, 'id=', identifier
  797.                                 if elem.strip().lower() == identifier.strip().lower():
  798.                                     create = False
  799.                                     break
  800.                 
  801.                 if create:
  802.                     self.globaldict[section][position] = []
  803.                     self.addOption(section, option, value=identifier, position=position)
  804.                     self.identifiers[section].append((identifier, position))#ADD to identifiers
  805.                     #print 'Created section', section, 'id =', identifier, 'position =', position
  806.                 #else:
  807.                     #print section, 'Section labelled as', identifier, 'already exists. None will be created.'
  808.             else:
  809.                 raise IdentifierException('%s Section requires an identifier' %(section))
  810.         else:
  811.             self.globaldict[section][position] = []
  812.         return position
  813.     
  814.     def removeSection(self, section, identifier=None, position=None):
  815.         '''Remove Sections by identifier, position or type'''
  816.         # Remove any section of "section" type with the same identifier
  817.         # currently sections of the same type cannot have the same id
  818.         # for obvious reasons
  819.         toremove = {}
  820.         if identifier:
  821.             try:
  822.                 pos = self.getPosition(section, identifier)
  823.                 toremove.setdefault(pos, None)
  824.             except IdentifierException:
  825.                 pass
  826.                     
  827.         # Comment the section of "section" type at position "position"
  828.         elif position != None:
  829.             if self.isSection(section, position=position):
  830.                 toremove.setdefault(position, None)
  831.         
  832.         # Comment any section of "section" type
  833.         else:
  834.             allkeys = self.globaldict[section].keys()
  835.             toremove = {}.fromkeys(allkeys)
  836.         
  837.         # If the section has an identifier i.e. if the section
  838.         # is in self.requireid
  839.         if section in self.requireid:
  840.             # Get the references to remove from self.identifiers 
  841.             it = 0
  842.             for reference in self.identifiers[section]:
  843.                 try:
  844.                     ref = toremove.keys().index(reference[1])
  845.                     toremove[toremove.keys()[ref]] = it
  846.                 except ValueError:
  847.                     pass
  848.                 it += 1
  849.         
  850.         sortedRemove = toremove.keys()
  851.         sortedRemove.sort()
  852.         
  853.         modded = 0
  854.         for sect in sortedRemove:
  855.             subsections = self.getSubSections(section, sect)
  856.             
  857.             # Remove all its SubSections from SubSection
  858.             for sub in subsections:
  859.                 try:#remove subsection
  860.                     del self.globaldict[self.subsection][sub]
  861.                 except KeyError:
  862.                     pass
  863.             
  864.             # Remember to remove any related entry from the "Comments"
  865.             # section
  866.             self.__removeCommentEntries(section, sect)
  867.         
  868.             # Remove the section from globaldict
  869.             del self.globaldict[section][sect]
  870.             
  871.             # Remove the reference from identifiers
  872.             # if such reference exists
  873.             identref = toremove[sect]
  874.             if identref != None:
  875.                 realpos = identref - modded
  876.  
  877.                 del self.identifiers[section][realpos]
  878.                 modded += 1
  879.  
  880.     
  881.     def addReference(self, section, reference, identifier, position=None):
  882.         '''Add a reference to a section from another section.
  883.         
  884.         For example:
  885.         to put a reference to the Screen section named "Default Screen"
  886.         in the ServerLayout section you should do:
  887.         
  888.         section='ServerLayout'
  889.         reference='Screen'
  890.         identifier='Default Screen'
  891.         position=0 #the first ServerLayout section
  892.         
  893.         NOTE: if position is set to None it will add such reference to any
  894.         instance of the section (e.g. to any ServerLayout section)'''
  895.         
  896.         self.addOption(section, reference, value=identifier, position=position, reference=True)
  897.         
  898.     def removeReference(self, section, reference, identifier, position=None):
  899.         '''Remove a reference to a section from another section.
  900.         
  901.         For example:
  902.         to remove a reference to Screen "Default Screen" from the
  903.         ServerLayout section you should do:
  904.         
  905.         section='ServerLayout'
  906.         reference='Screen'
  907.         identifier='Default Screen'
  908.         position=0 #the first ServerLayout section
  909.                 
  910.         NOTE: if position is set to None it will remove such reference from any
  911.         instance of the section (e.g. from any ServerLayout section)'''
  912.         
  913.         self.removeOption(section, reference, value=identifier, position=position, reference=True)
  914.     
  915.     def getReferences(self, section, position, reflist=None):
  916.         '''Get the references to other sections which are located in a section.
  917.         
  918.         section= the section (e.g. "Screen")
  919.         position= e.g. 0 stands for the 1st Screen section
  920.         reflist= a list of references which this function should look for.
  921.                  The default list of references is self.requireid but this
  922.                  list can be overridden by the reflist argument so that, for
  923.                  example, if reflist is set to ['Device'], this function will
  924.                  look for references to other devices only (references to, say,
  925.                  screens, will be ignored).'''
  926.         
  927.         if reflist == None:
  928.             options = self.requireid
  929.         else:
  930.             # if the following operation fails
  931.             # an AttributeError will be raised
  932.             # since reflist must be a list
  933.             reflist.append('')
  934.             del reflist[-1]
  935.             options = reflist
  936.         references = {}.fromkeys(options)
  937.         for option in options:
  938.             references[option] = []
  939.             referenceDict = {}
  940.             try:
  941.                 ref = self.getValue(section, option, position, reference=True)
  942.             except OptionException:
  943.                 ref = []
  944.             if ref:
  945.                 try:#if ref is already a list
  946.                     ref.append('')
  947.                     del ref[-1]
  948.                     
  949.                     for elem in ref:
  950.                         try:
  951.                             elem.append('')
  952.                             del elem[-1]
  953.                             for extref in elem:
  954.                                 if elem:
  955.                                     referenceDict.setdefault(extref)
  956.                         except AttributeError:# if ref is a string
  957.                             if elem:
  958.                                 referenceDict.setdefault(elem)
  959.                 except AttributeError:# if ref is a string
  960.                     if ref:
  961.                         referenceDict.setdefault(ref)
  962.                 for reference in referenceDict.keys():
  963.                     references[option].append(reference)
  964.         return references
  965.     
  966.     def makeSubSection(self, section, identifier, position=None):
  967.         '''Create a new subsection inside of a section.
  968.         
  969.         section= the section to which the subsection will belong
  970.         identifier= the name of the subsection
  971.         position= the position of the section in the dictionary with the
  972.              sections (e.g. the 1st "Screen" section would be 0). If set to
  973.              None it will create a new subsection in all the instances of
  974.              the said section (e.g. in all the "Screen" sections)'''
  975.         
  976.         curlength = len(self.globaldict[self.subsection])
  977.         
  978.         if position == None:
  979.             for elem in self.globaldict[section]:
  980.                 # don't create a new subsection if one with the same 'section', 'identifier'
  981.                 # and 'position' is found
  982.                 create = True
  983.                 for sub in self.globaldict[self.subsection]:
  984.                     if self.globaldict[self.subsection][sub].get('section') == section and \
  985.                     self.globaldict[self.subsection][sub].get('identifier') == identifier and\
  986.                     self.globaldict[self.subsection][sub].get('position') == elem:
  987.                         create = False
  988.                 
  989.                 if create:
  990.                     self.globaldict[self.subsection][curlength] = {}
  991.                     self.globaldict[self.subsection][curlength]['section'] = section
  992.                     self.globaldict[self.subsection][curlength]['identifier'] = identifier
  993.                     self.globaldict[self.subsection][curlength]['options'] = []
  994.                     self.globaldict[self.subsection][curlength]['position'] = elem
  995.                     curlength += 1
  996.         else:
  997.             # don't create a new subsection if one with the same 'section', 'identifier'
  998.             # and 'position' is found
  999.             create = True
  1000.             for sub in self.globaldict[self.subsection]:
  1001.                 if self.globaldict[self.subsection][sub].get('section') == section and \
  1002.                 self.globaldict[self.subsection][sub].get('identifier') == identifier and\
  1003.                 self.globaldict[self.subsection][sub].get('position') == position:
  1004.                     create = False
  1005.             
  1006.             if create:
  1007.                 self.globaldict[self.subsection][curlength] = {}
  1008.                 self.globaldict[self.subsection][curlength]['section'] = section
  1009.                 self.globaldict[self.subsection][curlength]['identifier'] = identifier
  1010.                 self.globaldict[self.subsection][curlength]['options'] = []
  1011.                 self.globaldict[self.subsection][curlength]['position'] = position
  1012.     
  1013.     def removeSubSection(self, section, identifier, position=None):
  1014.         '''Remove a subsection from one or more sections.
  1015.         
  1016.         section= the section to which the subsection belongs
  1017.         identifier= the name of the subsection
  1018.         position= the position of the section in the dictionary with the
  1019.              sections (e.g. the 1st "Screen" section would be 0). If set to
  1020.              None it will remove a subsection from all the instances of
  1021.              the said section (e.g. in all the "Screen" sections)'''
  1022.         
  1023.         curlength = len(self.globaldict[self.subsection])
  1024.         toremove = []
  1025.         if position == None:
  1026.             for elem in self.globaldict[self.subsection]:
  1027.                 if self.globaldict[self.subsection][elem].get('section') == section \
  1028.                 and self.globaldict[self.subsection][elem].get('identifier') == identifier:
  1029.                     toremove.append(elem)
  1030.                 
  1031.         else:
  1032.             for elem in self.globaldict[self.subsection]:
  1033.                 if self.globaldict[self.subsection][elem].get('section') == section \
  1034.                 and self.globaldict[self.subsection][elem].get('identifier') == identifier \
  1035.                 and self.globaldict[self.subsection][elem].get('position') == position:
  1036.                     toremove.append(elem)
  1037.         for item in toremove:
  1038.             del self.globaldict[self.subsection][item]
  1039.     
  1040.     def addSubOption(self, section, identifier, option, value, optiontype=None, position=None):
  1041.         '''Add an option to one or more subsections.
  1042.         
  1043.         section= the section which contains the subsection
  1044.         identifier= the identifier of the SubSection (e.g. Display)
  1045.         option= the option to add
  1046.         value= the value which will be assigned to the option
  1047.         optiontype= if set to "Option" it will cause the option to look like
  1048.                     the following:
  1049.                     Option "NameOfTheOption" "Value"
  1050.                     
  1051.                     Otherwise it will look like the following:
  1052.                     NameOfTheOption "Value"
  1053.         position= e.g. 0 (i.e. the option will be added to a subsection which
  1054.                   is located in the first element in the list of Screen
  1055.                   sections)'''
  1056.         
  1057.         prefix = '"'
  1058.         donotcreate = []
  1059.         tomodify = []
  1060.         if position == None:
  1061.             self.removeSubOption(section, identifier, option)
  1062.         else:
  1063.             self.removeSubOption(section, identifier, option, position=position)        
  1064.         if optiontype == None:
  1065.             toadd = '\t' + option + '\t' + str(value) + '\n'
  1066.         else:
  1067.             toadd = '\t' + optiontype + '\t' + prefix + option + prefix + '\t' \
  1068.             + prefix + str(value) + prefix + '\n'
  1069.         
  1070.         curlength = len(self.globaldict[self.subsection])
  1071.         if curlength == 0:
  1072.             self.globaldict[self.subsection][0] = {'section': section,
  1073.             'identifier': identifier, 'options': []}
  1074.         
  1075.         if position == None:
  1076.             # if there is not a subsection for each selected section then
  1077.             # create it
  1078.             cursectlength = len(self.globaldict[section])
  1079.             it = 0
  1080.             while it < cursectlength:
  1081.                 for elem in self.globaldict[self.subsection]:
  1082.                     if self.globaldict[self.subsection][elem].get("position") == it and \
  1083.                     self.globaldict[self.subsection][elem].get("section") == section and \
  1084.                     self.globaldict[self.subsection][elem].get("identifier") == identifier:
  1085.                         donotcreate.append(it)
  1086.                 it += 1
  1087.             for i in range(cursectlength+1):
  1088.                 if i not in donotcreate:
  1089.                     self.makeSubSection(section, identifier, position=i)
  1090.  
  1091.             for elem in self.globaldict[self.subsection]:
  1092.                 if self.globaldict[self.subsection][elem].get("identifier") == identifier and \
  1093.                 self.globaldict[self.subsection][elem].get("section") == section:
  1094.                     tomodify.append(elem)
  1095.                     
  1096.         else:
  1097.             for elem in self.globaldict[self.subsection]:
  1098.                 if self.globaldict[self.subsection][elem].get("position") == position and \
  1099.                 self.globaldict[self.subsection][elem].get("identifier") == identifier:
  1100.                     tomodify.append(elem)
  1101.             if len(tomodify) == 0:
  1102.                 curlength = len(self.globaldict[self.subsection])
  1103.                 self.globaldict[self.subsection][len(self.globaldict[self.subsection])] = \
  1104.                 {'section': section, 'identifier': identifier,
  1105.                      'options': [], 'position': position}
  1106.                 tomodify.append(curlength)
  1107.         
  1108.         for elem in tomodify:
  1109.             self.globaldict[self.subsection][elem]['options'].append(toadd)
  1110.         
  1111.     
  1112.     def __getSubOptionsToBlacklist(self, section, identifier, option, position=None):
  1113.         '''Get a dictionay of the suboptions to blacklist.
  1114.         
  1115.         See addSubOption() for an explanation on the arguments.
  1116.         
  1117.         Used in both removeOption() and removeSubOption()
  1118.         '''
  1119.         toremove = {}
  1120.         if len(self.globaldict[section]) != 0:#if the section exists
  1121.             if len(self.globaldict[self.subsection]) != 0:
  1122.                 for elem in self.globaldict[self.subsection]:
  1123.                     if position == None:
  1124.                         if self.globaldict[self.subsection][elem].get('section') == section \
  1125.                         and self.globaldict[self.subsection][elem].get('identifier') == identifier:
  1126.                             it = 0
  1127.                             for opt in self.globaldict[self.subsection][elem]['options']:
  1128.                                 if opt.strip().lower().find(option.strip().lower()) != -1:
  1129.                                     toremove.setdefault(elem, []).append(it)
  1130.                                 it += 1
  1131.                     else:
  1132.                         if self.globaldict[self.subsection][elem].get('section') == section \
  1133.                         and self.globaldict[self.subsection][elem].get('identifier') == identifier \
  1134.                         and self.globaldict[self.subsection][elem].get('position') == position:
  1135.                             it = 0
  1136.                             for opt in self.globaldict[self.subsection][elem]['options']:
  1137.                                 if opt.strip().lower().find(option.strip().lower()) != -1:
  1138.                                     toremove.setdefault(elem, []).append(it)
  1139.                                 it += 1
  1140.         return toremove
  1141.  
  1142.  
  1143.     def removeSubOption(self, section, identifier, option, position=None):
  1144.         '''Remove an option from a subsection.'''
  1145.         
  1146.         toremove = self.__getSubOptionsToBlacklist(section, identifier, option, position)
  1147.         for elem in toremove:
  1148.             modded = 0
  1149.             for part in toremove[elem]:
  1150.                 realpos = part - modded
  1151.                 del self.globaldict[self.subsection][elem]['options'][realpos]
  1152.                 modded += 1
  1153.  
  1154.     def getIdentifier(self, section, position):
  1155.         '''Get the identifier of a specific section from its position.'''
  1156.         
  1157.         errorMsg = 'No identifier can be found for section "%s" No %d' %(section, position)
  1158.         try:
  1159.             for sect in self.identifiers[section]:
  1160.                 if sect[1] == position:
  1161.                     return sect[0]
  1162.         except KeyError:
  1163.             raise SectionException
  1164.         raise IdentifierException, errorMsg
  1165.  
  1166.  
  1167.     def __cleanOption(self, option, optname, reference=None, section=None):
  1168.         '''Clean the option and return the value (i.e. the last item of the list
  1169.         which this method generates).
  1170.         
  1171.         If no value can be found, return False.'''
  1172.         
  1173.         if reference:
  1174.             # If it's a reference to another section then options such as
  1175.             # Option    "Device"    "/dev/psaux" should not be taken into
  1176.             # account.
  1177.             if 'option' in option.strip().lower():
  1178.                 return False
  1179.             
  1180.             # Do not confuse Device "Configure device" with InputDevice "device"
  1181.             if not option.strip().lower().startswith(optname.strip().lower()):
  1182.                 return False
  1183.                 
  1184.         optbits = []
  1185.         optbit = ''
  1186.         it = 0
  1187.         quotation = 0
  1188.         optcount = option.count('"')
  1189.         if optcount > 0:#dealing with a section option
  1190.             for i in option:
  1191.                 if optcount in [2, 4] and section == 'ServerLayout':
  1192.                     if not i.isspace():
  1193.                         if i == '"':
  1194.                             if quotation != 0 and quotation % 2 != 0:
  1195.                                 if len(optbit) > 0:
  1196.                                     optbits.append(optbit)
  1197.                                     optbit = ''
  1198.                             quotation += 1
  1199.                         else:
  1200.                             if quotation % 2 != 0:
  1201.                                 optbit += i
  1202.                     else:    
  1203.                     
  1204.                         if quotation % 2 != 0:
  1205.                             optbit += i
  1206.                 else:
  1207.                     #print 'i', repr(i), 'optbit', optbit
  1208.                     if not i.isspace():
  1209.                         if i == '"':
  1210.                             quotation += 1
  1211.                         else:
  1212.                             optbit += i
  1213.                     else:    
  1214.                     
  1215.                         if quotation % 2 != 0:
  1216.                             optbit += i
  1217.                             
  1218.                         else:
  1219.                             if len(optbit) > 0:
  1220.                                 optbits.append(optbit)
  1221.                                 #print 'i=', i, 'optbit=', optbit
  1222.                                 optbit = ''
  1223.                         
  1224.                 if it == len(option) - 1:
  1225.                     if optbit != '':
  1226.                         optbits.append(optbit)
  1227.                         #print 'i=END', 'optbit=', optbit
  1228.                 it += 1            
  1229.         else:#dealing with a subsection option
  1230.             for i in option:
  1231.                 #print 'i', repr(i), 'optbit', optbit
  1232.                 if not i.isspace():
  1233.                     optbit += i
  1234.                 else:    
  1235.                     if len(optbit) > 0:
  1236.                         optbits.append(optbit)
  1237.                         #print 'i=', i, 'optbit=', optbit
  1238.                         optbit = ''
  1239.                         
  1240.                 if it == len(option) - 1:
  1241.                     if optbit != '':
  1242.                         optbits.append(optbit)
  1243.                         #print 'i=END', 'optbit=', optbit
  1244.                 it += 1
  1245.         
  1246.         optlen = len(optbits)
  1247.  
  1248.         if optlen > 1:
  1249.             # Let's make sure that the option is the one we're looking for
  1250.             # e.g. if we're looking for a reference to Device we are not
  1251.             # interested in getting references to InputDevice
  1252.             
  1253.             referencesList = [x.lower().strip() for x in self.references]
  1254.             
  1255.             if section != 'ServerLayout' and quotation == 0 and optlen == 2 and optbits[0].lower().strip() in referencesList:
  1256.                 # e.g. Screen 1 -> 1 stands for the position, therefore the 
  1257.                 # identifier of the section at position 1 should be returned
  1258.                 # instead of the number (if possible).
  1259.                 # 
  1260.                 # return [Screen, identifier]
  1261.                 try:
  1262.                     sect = ''
  1263.                     value = int(optbits[1].strip())
  1264.                     for item in self.requireid:
  1265.                         if optbits[0].lower().strip() == item.lower().strip():
  1266.                             sect = item
  1267.                             break
  1268.                     try:                     
  1269.                         identifier = self.getIdentifier(sect, value)
  1270.                         return [identifier]
  1271.                     except (IdentifierException):
  1272.                         return False
  1273.                 except ValueError:
  1274.                     pass
  1275.             
  1276.             if optcount != 4 and section != 'ServerLayout':
  1277.                 status = False
  1278.                 for elem in optbits:
  1279.                     if elem.lower() == optname.lower():
  1280.                         status = True
  1281.                 if status == False:
  1282.                     return False
  1283.                 
  1284.             if optlen == 2 and optbits[0].lower().strip() == 'option':
  1285.                 # e.g. Option "AddARGBGLXVisuals"
  1286.                 # (The value was omitted but it will be interpreted as True by
  1287.                 # Xorg)
  1288.                 return 'True'
  1289.             
  1290.             sections = [sect.strip().lower() for sect in self.sections]
  1291.             
  1292.             
  1293. #            if optlen == 2 and optbits[0].lower().strip() in sections:
  1294. #                '''
  1295. #                Do not confuse Device "Configure device" with InputDevice "device"
  1296. #                '''
  1297. #                if optbits[0].lower().strip() != optname.strip().lower():
  1298. #                    return False
  1299.             
  1300.             if optcount == 4 and section == 'ServerLayout':
  1301.                 #If it's something like InputDevice "stylus" "SendCoreEvents"
  1302.                 if optname.lower().strip() == 'inputdevice' and len(optbits) == 2:
  1303.                     del optbits[1]
  1304.                 serverDict = {}
  1305.                 for elem in optbits:
  1306.                     serverDict.setdefault(elem)
  1307.                 return serverDict.keys()
  1308.             elif optcount > 0 and optcount <= 4:#dealing with a section option
  1309.                 return optbits[optlen -1]
  1310.             elif optcount > 4:
  1311.                 del optbits[0]
  1312.                 return optbits
  1313.             elif optcount == 0:
  1314.                 del optbits[0]
  1315.                 return ' '.join(optbits)
  1316.         else:
  1317.             if optcount in [2, 4] and section == 'ServerLayout':
  1318.                 return optbits
  1319.             return False
  1320.  
  1321.     def getValue(self, section, option, position, identifier=None, sect=None, reference=None):
  1322.         '''Get the value which is assigned to an option.
  1323.         
  1324.         Return types:
  1325.           * string (if only one value is available)
  1326.             - usually in options
  1327.           * list (if more than one option is found)
  1328.             - having multiple references of the same type is allowed.
  1329.               for example it is not unusual to have 2 references to
  1330.               Screen sections in the ServerLayout section (in case of
  1331.               Xinerama)
  1332.             - if the options are actually options and not references
  1333.               then there are duplicate options, which should be detected
  1334.               in advance with xutils.XUtils.getDuplicateOptions()   
  1335.           * None (if no value can be found) - Not always true -> See below.
  1336.         
  1337.         NOTE: Use-case for returning None
  1338.             * When dealing with incomplete references. For example:
  1339.                   Screen "Configured Screen"
  1340.                 is different from:
  1341.                   Screen
  1342.                   (which is an incomplete reference)
  1343.             * When dealing with incomplete options. For example:
  1344.                   Depth 24
  1345.                 is different from:
  1346.                   Depth
  1347.                   (which is an incomplete option)
  1348.             * Exception:
  1349.                 Some options (with the "Option" prefix) (not references)
  1350.                 can be used with no value (explicitly) assigned and are
  1351.                 considered as True by the Xserver. In such case getValue()
  1352.                 will return "True". For example:
  1353.                   Option "AddARGBGLXVisuals" 
  1354.                 is the same as:
  1355.                   Option "AddARGBGLXVisuals" "True"
  1356.         
  1357.         NOTE: Meaning of keys in Sections and SubSections:
  1358.             * When dealing with a Section:
  1359.                 section= e.g. 'Screen', 'Device', etc.
  1360.                 option= the option
  1361.                 position= e.g. 0 (i.e. the first element in the list of Screen
  1362.                           sections)
  1363.                 reference= used only by getReferences()
  1364.             
  1365.             * When dealing with a SubSection:
  1366.                 section= 'SubSection' (this is mandatory)
  1367.                 option= the option
  1368.                 position= e.g. 0 would mean that the subsection belongs to 
  1369.                           the 1st item of the list of, say, "Screen" sections.
  1370.                           (i.e. the first element in the list of Screen 
  1371.                           sections)
  1372.                           ["position" is a key of an item of the list of 
  1373.                           subsections see below]
  1374.                 
  1375.                 identifier= the name of the subsection e.g. 'Display'
  1376.                 sect = the 'section' key of an item of the list of 
  1377.                        subsections e.g. the "Display" subsection can be 
  1378.                        found in the "Screen" section ('sect' is the latter)
  1379.             
  1380.         NOTE: Anatomy of Sections and SubSections:
  1381.             * Anatomy of subsections:
  1382.                 self.globaldict['SubSection'] =
  1383.                     {0: {'section': 'Screen', 'identifier': 'Display', 
  1384.                     'position': 0, 'options': [option1, option2, etc.], 
  1385.                     etc.}
  1386.                     In this case we refer to the 'Display' subsection 
  1387.                     which is located in the first 'Screen' section.
  1388.             
  1389.             * Anatomy of a section:
  1390.                 self.globaldict['Screen'] =
  1391.                     {0: [option1, option2, etc.], 1: [...], ...}
  1392.                 0, 1, etc. is the position '''
  1393.         
  1394.         values = []
  1395.         
  1396.         if self.globaldict[section].get(position) == None:
  1397.             raise SectionException
  1398.             
  1399.             #if len(values) == 0:
  1400.                 #raise OptionException
  1401.             
  1402.             #return values
  1403.         
  1404.         else:
  1405.             try:
  1406.                 # see if it's a dictionary (e.g. in case of a subsection)
  1407.                 # or a list (in case of a normal section) and act
  1408.                 # accordingly
  1409.                 self.globaldict[section][position].index('foo')
  1410.             except AttributeError:#dict
  1411.                 if identifier == None:
  1412.                     raise Exception('An identifier is required for subsections')
  1413.                 else:
  1414.                     for elem in self.globaldict[section]:
  1415.                         if self.globaldict[section][elem].get('identifier') == identifier and \
  1416.                         self.globaldict[section][elem].get('position') == position and \
  1417.                         self.globaldict[section][elem].get('section') == sect:
  1418.                             for opt in self.globaldict[section][elem]['options']:
  1419.                                 if option.strip().lower() in opt.strip().lower():
  1420.                                     if opt.strip().find('#') != -1:
  1421.                                         stropt = opt.strip()[0: opt.strip().find('#')]
  1422.                                     else:
  1423.                                         stropt = opt.strip()
  1424.                                     # clean the option and return the value
  1425.                                     values.append(self.__cleanOption(stropt, option, reference=reference))
  1426.                     
  1427.                     if len(values) == 0:
  1428.                         raise OptionException
  1429.                     
  1430.                     if len(values) > 1:
  1431.                         return values
  1432.                     else:
  1433.                         try:
  1434.                             return values[0]
  1435.                         except IndexError:
  1436.                             return None
  1437.  
  1438.             except ValueError:#list
  1439.                 for elem in self.globaldict[section][position]:
  1440.                     if option.strip().lower() in elem.strip().lower():
  1441.                         # clean the option and return the value
  1442.                         if elem.strip().find('#') != -1:
  1443.                             stropt = elem.strip()[0: elem.strip().find('#')]
  1444.                         else:
  1445.                             stropt = elem.strip()
  1446.                         values.append(self.__cleanOption(stropt, option, reference=reference, section=section))
  1447.                 
  1448.                 if len(values) == 0:
  1449.                     raise OptionException
  1450.                 
  1451.                 if len(values) > 1:
  1452.                     return values
  1453.                 else:
  1454.                     try:
  1455.                         return values[0]
  1456.                     except IndexError:
  1457.                         return None
  1458.             except KeyError:#not found
  1459.                 raise OptionException
  1460.     
  1461.     def isSection(self, section, identifier=None, position=None):
  1462.         '''See if a section with a certain identifier exists.
  1463.         
  1464.         NOTE: either identifier or position must be provided.'''
  1465.         
  1466.         if identifier != None:
  1467.             try:
  1468.                 self.getPosition(section, identifier)
  1469.                 return True
  1470.             except IdentifierException:
  1471.                 return False
  1472.         elif position != None:
  1473.             return self.globaldict[section].get(position) != None
  1474.         
  1475.         else:
  1476.             errorMsg = 'Either identifier or position must be provided'
  1477.             raise Exception(errorMsg)
  1478.     
  1479.     def getPosition(self, section, identifier):
  1480.         '''Get the position of a specific section from its identifier.'''
  1481.         
  1482.         errorMsg = 'No %s section named "%s" can be found' %(section, identifier)
  1483.         for sect in self.identifiers[section]:
  1484.             try:
  1485.                 if sect[0].strip().lower() == identifier.strip().lower():
  1486.                     return sect[1]
  1487.             except AttributeError:
  1488.                 pass
  1489.         raise IdentifierException, errorMsg
  1490.     
  1491.     def getBrokenReferences(self):
  1492.         '''Look for broken references (i.e. references to sections which don't exist)
  1493.         and return a dictionary having the items of self.requireid as keys and
  1494.         a dictionary of the identifiers of the sections which are referred to by the
  1495.         broken references.
  1496.         
  1497.         For example:
  1498.         
  1499.         brokenReferences = {
  1500.                             'InputDevice': {'InputDevice 1': None, 'Another input device': None},
  1501.                             'Device': {...},
  1502.                             'Monitor' {...},
  1503.                             'Screen' {...},
  1504.                             'ServerLayout' {...}
  1505.                             }'''
  1506.         
  1507.         brokenReferences = {}.fromkeys(self.requireid)
  1508.         referencesTree = {}
  1509.         for section in self.requireid:#['Screen', 'ServerLayout']
  1510.             referencesTree[section] = {}
  1511.             brokenReferences[section] = {}
  1512.             for sect in self.globaldict[section]:
  1513.                 referencesTree[section][sect] = self.getReferences(section, sect)
  1514.         #print >> stderr, 'REFERENCES = %s' % (str(referencesTree))
  1515.         for section in referencesTree:
  1516.             for elem in referencesTree[section]:
  1517.                 for refsect in referencesTree[section][elem]:
  1518.                     
  1519.                     if len(referencesTree[section][elem][refsect]) > 0:
  1520.                         #referencesTree[section][elem][refsect]
  1521.                         for ref in referencesTree[section][elem][refsect]:
  1522.                             for sect in self.sections:
  1523.                                 if sect.lower() == refsect.strip().lower():
  1524.                                     refsect = sect
  1525.                             if not self.isSection(refsect, ref):
  1526.                                 #print '*****WARNING:', refsect, 'Section', ref, 'does not exist!*****'
  1527.                                 brokenReferences[refsect].setdefault(ref)
  1528.                                 #print 'FIX: Creating', refsect, 'Section', ref
  1529.                                 #self.makeSection(refsect, identifier=ref)
  1530.         return brokenReferences
  1531.     
  1532.     
  1533.     
  1534.     def getDefaultServerLayout(self):
  1535.         '''See if one or more ServerLayout sections are set as default and return their
  1536.         position in a list
  1537.         
  1538.         NOTE: If the section set as the default ServerLayout doesn't exist
  1539.               it will raise a ParseException.'''
  1540.         
  1541.         default = []
  1542.         serverFlags = self.globaldict['ServerFlags']
  1543.         it = 0
  1544.         for flag in serverFlags:
  1545.             try:
  1546.                 defaultLayout = self.getValue('ServerFlags', 'DefaultServerLayout', it)
  1547.                 if defaultLayout:
  1548.                     defIt = 0
  1549.                     for identifier in self.identifiers['ServerLayout']:
  1550.                         if identifier[0].lower().strip() == defaultLayout.lower().strip():
  1551.                             default.append(identifier[1])#LayoutPosition
  1552.                             defIt += 1
  1553.                     if defIt == 0:
  1554.                         # If the section set as the default ServerLayout doesn't exist
  1555.                         # raise a ParseException
  1556.                         error = 'The default ServerLayout does not exist.'
  1557.                         raise ParseException(error)
  1558.             except OptionException:#no defaultLayout
  1559.                 pass
  1560.             it += 1
  1561.         return default
  1562.     
  1563.  
  1564.     def __mergeSubSections(self):
  1565.         '''Put SubSections back into the sections to which they belong.'''
  1566.         
  1567.         for sect in self.tempdict['SubSection']:
  1568.             section = self.tempdict['SubSection'][sect]['section']
  1569.             identifier = self.tempdict['SubSection'][sect]['identifier']
  1570.             position = self.tempdict['SubSection'][sect].get('position')
  1571.             options = self.tempdict['SubSection'][sect]['options']
  1572.             self.tempdict[section].setdefault(position, []).append('\tSubSection ' + '"' + identifier + '"' + '\n')
  1573.             if len(options) > 0:
  1574.                 self.tempdict[section][position].append('\t' + '\t'.join(options) + '\tEndSubSection\n')
  1575.             else:
  1576.                 self.tempdict[section][position].append('\t'.join(options) + '\tEndSubSection\n')
  1577.         try:#remove subsection since it was merged
  1578.             del self.tempdict['SubSection']
  1579.         except KeyError:
  1580.             pass
  1581.             
  1582.     
  1583.     def writeFile(self, destination, test=None):
  1584.         '''Write the changes to the destination file (e.g. /etc/X11/xorg.conf)
  1585.         or file object (e.g. sys.stdout).
  1586.         
  1587.         * Arguments:
  1588.           destination = the destination file or file object (mandatory)
  1589.           test = if set to True writeFile will append the result to the
  1590.                  destination file instead of overwriting it. It has no 
  1591.                  effect on file objects. Useful for testing.
  1592.         
  1593.         NOTE: global dict's state is not altered.'''
  1594.         
  1595.         # Create self.tempdict
  1596.         self.tempdict = copy.deepcopy(self.globaldict)
  1597.         
  1598.         # Commented options must be dealt with first
  1599.         self.__mergeCommentedOptions()
  1600.         
  1601.         # Merge all the non-commented subsections
  1602.         self.__mergeSubSections()
  1603.         lines = []
  1604.         comments = ''.join(self.comments) + '\n'
  1605.         lines.append(comments)
  1606.         for section in self.tempdict:
  1607.             if section != self.commentsection:
  1608.                 if len(self.tempdict[section]) > 0:
  1609.                     for elem in self.tempdict[section]:
  1610.                         lines.append('Section ' + '"' + section + '"' + '\n')
  1611.                         lines.append(''.join(self.tempdict[section][elem]) + 'EndSection\n\n')
  1612.  
  1613.         del self.tempdict
  1614.         
  1615.         if not hasattr(destination, 'write'):#it is a file
  1616.             if test:
  1617.                 destination = open(destination, 'a')
  1618.             else:
  1619.                 destination = open(destination, 'w')
  1620.             destination.write(''.join(lines))
  1621.             destination.close()
  1622.         else:#it is a file object
  1623.             destination.write(''.join(lines))
  1624.     
  1625.     def getSubSections(self, section, position):
  1626.         '''Get all the subsections contained in a section'''
  1627.         # loop through subsections and see what subsections match
  1628.         # the section
  1629.         subsections = []
  1630.         for sub in self.globaldict[self.subsection]:
  1631.             if self.globaldict[self.subsection][sub]['section'] == section \
  1632.             and self.globaldict[self.subsection][sub]['position'] == position:
  1633.                 subsections.append(sub)
  1634.         
  1635.         return subsections
  1636.     
  1637.     def __permanentMergeSubSections(self, subsections):
  1638.         '''Put SubSections back into the sections to which they belong and comment them out
  1639.         
  1640.         WARNING: this alters globaldict and should be used only in commentOutSection()
  1641.                  i.e. when the whole section is being commented out.
  1642.                   
  1643.         subsections = the list of the indices subsections to merge and remove'''
  1644.         
  1645.         for sect in subsections:
  1646.             section = self.globaldict[self.subsection][sect]['section']
  1647.             identifier = self.globaldict[self.subsection][sect]['identifier']
  1648.             position = self.globaldict[self.subsection][sect].get('position')
  1649.             options = self.globaldict[self.subsection][sect]['options']
  1650.             self.comments.append('#\tSubSection ' + '"' + identifier + '"' + '\n')
  1651.  
  1652.             for option in options:
  1653.                 opt = '#\t\t%s\n' % (option.strip())
  1654.                 self.comments.append(opt)
  1655.                 self.comments.append('#\tEndSubSection\n')
  1656.  
  1657.             try:#remove subsection since it was merged
  1658.                 del self.globaldict[self.subsection][sect]
  1659.             except KeyError:
  1660.                 pass
  1661.     
  1662.     def __getComments(self, section, position):
  1663.         '''Return the index of the comment entry in the Comments section for a section'''
  1664.         
  1665.         comments = []
  1666.         if self.globaldict[self.commentsection].get(section):
  1667.             for sect in self.globaldict[self.commentsection][section]:
  1668.                 if self.globaldict[self.commentsection][section][sect].get('position') == position:
  1669.                     comments.append(sect)
  1670.         
  1671.         return comments
  1672.     
  1673.     def __MergeSubSectionsWithComments(self, subsections):
  1674.         '''Put SubSections back into the sections to which they belong and comment them out
  1675.         
  1676.         WARNING: this alters globaldict and should be used only to comment out subsections
  1677.                  (i.e. in commentOutSubSection() ) when the whole section is not being 
  1678.                  commented out
  1679.                  
  1680.         subsections = the list of the indices subsections to merge and remove'''
  1681.         
  1682.         endSubSection = '#\tEndSubSection\n'
  1683.         
  1684.         for sect in subsections:
  1685.             section = self.globaldict[self.subsection][sect]['section']
  1686.             identifier = self.globaldict[self.subsection][sect]['identifier']
  1687.             position = self.globaldict[self.subsection][sect].get('position')
  1688.             options = self.globaldict[self.subsection][sect]['options']
  1689.             
  1690.             startSubSection = '#\tSubSection "%s"\n' % (identifier)
  1691.             
  1692.             comments = self.__getComments(section, position)
  1693.             if not comments:
  1694.                 self.globaldict[self.commentsection][section] = {}
  1695.                 self.globaldict[self.commentsection][section][position] = {}
  1696.                 self.globaldict[self.commentsection][section][position]['identifier'] = None
  1697.                 self.globaldict[self.commentsection][section][position]['position'] = position
  1698.                 self.globaldict[self.commentsection][section][position]['section'] = None
  1699.                 self.globaldict[self.commentsection][section][position]['options'] = []
  1700.                 
  1701.                 
  1702.             comments_options = self.globaldict[self.commentsection][section][position]['options']
  1703.             
  1704.             comments_options.append(startSubSection)
  1705.             for option in options:
  1706.                 opt = '#\t\t%s\n' % (option.strip())
  1707.                 comments_options.append(opt)
  1708.             
  1709.             comments_options.append(endSubSection)
  1710.             
  1711.             #remove subsection since it was merged
  1712.             del self.globaldict[self.subsection][sect]
  1713.     
  1714.     def __commentOutRelatedSubSections(self, section, position):
  1715.         '''Comment out all the subsections of a section.'''
  1716.         
  1717.         subsections = self.getSubSections(section, position)
  1718.         self.__permanentMergeSubSections(subsections)
  1719.     
  1720.     def __removeCommentEntries(self, section, position):
  1721.         '''Remove comment sections of specific sections from the "Comments" section'''
  1722.         
  1723.         comments = self.__getComments(section, position)
  1724.         for commentSection in comments:
  1725.             del self.globaldict['Comments'][section][commentSection]
  1726.     
  1727.     def commentOutSection(self, section, identifier=None, position=None):
  1728.         '''Comment out a section and all its subsections.'''
  1729.         
  1730.         startSection = '\n#Section "%s"\n' % (section)
  1731.         endSection = '#EndSection\n'
  1732.  
  1733.         # Comment any section of "section" type with the same identifier
  1734.         #   currently sections of the same type cannot have the same id
  1735.         #   for obvious reasons
  1736.         toremove = {}
  1737.         if identifier:
  1738.             try:
  1739.                 pos = self.getPosition(section, identifier)
  1740.                 toremove.setdefault(pos, None)
  1741.             except IdentifierException:
  1742.                 pass
  1743.                     
  1744.         # Comment the section of "section" type at position "position"
  1745.         elif position != None:
  1746.             if self.isSection(section, position=position):
  1747.                 toremove.setdefault(position, None)
  1748.         
  1749.         # Comment any section of "section" type
  1750.         else:
  1751.             allkeys = self.globaldict[section].keys()
  1752.             toremove = {}.fromkeys(allkeys)
  1753.         
  1754.         # If the section has an identifier i.e. if the section
  1755.         # is in self.requireid
  1756.         if section in self.requireid:
  1757.             # Get the references to remove from self.identifiers 
  1758.             it = 0
  1759.             for reference in self.identifiers[section]:
  1760.                 try:
  1761.                     ref = toremove.keys().index(reference[1])
  1762.                     toremove[toremove.keys()[ref]] = it
  1763.                 except ValueError:
  1764.                     pass
  1765.                 it += 1
  1766.         
  1767.         
  1768.         sortedRemove = toremove.keys()
  1769.         sortedRemove.sort()
  1770.         
  1771.         
  1772.         modded = 0
  1773.         for sect in sortedRemove:
  1774.             self.comments.append(startSection)
  1775.             for option in self.globaldict[section][sect]:
  1776.                 commentedOption = '#\t%s\n' % (option.strip())
  1777.                 self.comments.append(commentedOption)
  1778.  
  1779.             # Append all its SubSections (automatically commented
  1780.             #  out) and remove them from SubSection
  1781.             self.__commentOutRelatedSubSections(section, sect)
  1782.             self.comments.append(endSection)
  1783.             
  1784.             # Remember to remove any related entry from the "Comments"
  1785.             # section
  1786.             self.__removeCommentEntries(section, sect)
  1787.         
  1788.             # Remove the section from globaldict
  1789.             del self.globaldict[section][sect]
  1790.             
  1791.             # Remove the reference from identifiers
  1792.             # if such reference exists
  1793.             identref = toremove[sect]
  1794.             if identref != None:
  1795.                 realpos = identref - modded
  1796.  
  1797.                 del self.identifiers[section][realpos]
  1798.                 modded += 1
  1799.  
  1800.     
  1801.     def commentOutSubSection(self, section, identifier, position):
  1802.         '''Comment out a subsection.
  1803.         
  1804.         section= the type of the section which contains the subsection
  1805.         identifier= the identifier of the subsection
  1806.         position= the position of the section'''
  1807.         
  1808.         subsections = []
  1809.         for subsection in self.globaldict[self.subsection]:
  1810.             if self.globaldict[self.subsection][subsection]['section'] == section \
  1811.             and self.globaldict[self.subsection][subsection]['identifier'] == identifier \
  1812.             and self.globaldict[self.subsection][subsection]['position'] == position:
  1813.                 subsections.append(subsection)
  1814.                 break
  1815.         # Add the subsection to the Comments section
  1816.         self.__MergeSubSectionsWithComments(subsections)
  1817.         
  1818.     
  1819.     def commentOutOption(self, section, option, value=None, position=None, reference=None):
  1820.         '''Comment out an option in a section.
  1821.         
  1822.         section= the section which will have the option commented out
  1823.         option= the option to comment out
  1824.         value= if you want to comment out an option only if it has a certain value
  1825.         position= e.g. 0 (i.e. the first element in the list of Screen
  1826.                       sections)'''
  1827.         
  1828.         toremove = self.__getOptionsToBlacklist(section, option, value, position, reference)
  1829.         for part in toremove:
  1830.             modded = 0
  1831.             for line in toremove[part]:
  1832.                 realpos = line - modded
  1833.                 self.globaldict[section][part][realpos] = '#%s' % (self.globaldict[section][part][realpos].strip())
  1834.                 
  1835.                 self.globaldict[self.commentsection].setdefault(section, {})
  1836.                 curlength = len(self.globaldict[self.commentsection][section])
  1837.                 self.globaldict[self.commentsection][section].setdefault(part, {})
  1838.                 self.globaldict[self.commentsection][section][part].setdefault('identifier', None)
  1839.                 self.globaldict[self.commentsection][section][part].setdefault('position', part)
  1840.                 self.globaldict[self.commentsection][section][part].setdefault('section', None)
  1841.                 self.globaldict[self.commentsection][section][part].setdefault('options', [])
  1842.                 # Copy the option to the Comments section
  1843.                 self.globaldict[self.commentsection][section][part]['options'].append(self.globaldict[section][part][realpos])
  1844.  
  1845.                 #Remove it from its section in globaldict
  1846.                 del self.globaldict[section][part][realpos]
  1847.                 
  1848.                 modded += 1
  1849.  
  1850.     
  1851.     def commentOutSubOption(self, section, identifier, option, position=None):
  1852.         '''Comment out an option in a subsection.
  1853.         
  1854.         section= the section which contains the subsection
  1855.         identifier= the identifier of the subsection
  1856.         option= the option to comment out
  1857.         position= the position of the section which contains the subsection
  1858.                   e.g. 0 (i.e. the first element in the list of Screen
  1859.                   sections)'''
  1860.         
  1861.         toremove = self.__getSubOptionsToBlacklist(section, identifier, option, position)
  1862.         for elem in toremove:
  1863.             modded = 0
  1864.             for part in toremove[elem]:
  1865.                 realpos = part - modded
  1866.                 
  1867.                 self.globaldict[self.subsection][part]['options'][realpos] = \
  1868.                 '#%s' % (self.globaldict[self.subsection][part]['options'][realpos].strip())
  1869.                 
  1870.                 self.globaldict[self.commentsection].setdefault(self.subsection, {})
  1871.                 curlength = len(self.globaldict[self.commentsection][self.subsection])
  1872.                 self.globaldict[self.commentsection][self.subsection].setdefault(part, {})
  1873.                 self.globaldict[self.commentsection][self.subsection][part].setdefault('identifier', identifier)
  1874.                 self.globaldict[self.commentsection][self.subsection][part].setdefault('position', part)
  1875.                 self.globaldict[self.commentsection][self.subsection][part].setdefault('section', section)
  1876.                 self.globaldict[self.commentsection][self.subsection][part].setdefault('options', [])
  1877.                 # Copy the option to the Comments section
  1878.                 commentsOptions = self.globaldict[self.commentsection][self.subsection][part]['options']
  1879.                 commentedOption = self.globaldict[self.subsection][part]['options'][realpos]
  1880.                 commentsOptions.append(commentedOption)
  1881.                 
  1882.                 #Remove the option from its section in globaldict
  1883.                 del self.globaldict[self.subsection][elem]['options'][realpos]
  1884.                 modded += 1
  1885.     
  1886.     def __mergeCommentedOptions(self):
  1887.         '''Put commented out options back into the sections or subsections to which they belong.'''
  1888.         
  1889.         for sect in self.tempdict[self.commentsection]:
  1890.             sectionOptions = None
  1891.             for sectionInstance in self.tempdict[self.commentsection][sect]:
  1892.                 section = self.tempdict[self.commentsection][sect][sectionInstance].get('section')
  1893.                     
  1894.                 identifier = self.tempdict[self.commentsection][sect][sectionInstance].get('identifier')
  1895.                 position = self.tempdict[self.commentsection][sect][sectionInstance].get('position')
  1896.                 options = self.tempdict[self.commentsection][sect][sectionInstance]['options']
  1897.                 if section == self.subsection:
  1898.                     for sub in self.tempdict[sect]:
  1899.                         subSection = self.tempdict[sect][sub]
  1900.                         if subSection['identifier'] == identifier and \
  1901.                         subSection['position'] == position and \
  1902.                         subSection['section'] == section:
  1903.                             sectionOptions = self.tempdict[sect][sub]['options']
  1904.                             break
  1905.                     
  1906.                 else:
  1907.                     sectionOptions = self.tempdict[sect].get(position)
  1908.             
  1909.             if sectionOptions:
  1910.                 for option in options:
  1911.                     option = '\t%s\n' % (option.strip())
  1912.                     if sect == self.subsection:
  1913.                         sectionOptions.setdefault('options', []).append(option)
  1914.                     else:
  1915.                         sectionOptions.append(option)
  1916.  
  1917.     
  1918.